import {
  Component,
  Host,
  h,
  ComponentInterface,
  Element,
  Prop,
  Event,
  EventEmitter,
  Method,
  writeTask,
  Watch,
  forceUpdate,
} from '@stencil/core';
import {
  attachComponent,
  ComponentRef,
  deepReady,
  detachComponent,
  dismiss,
  eventMethod,
  FrameworkDelegate,
  hidden,
  ModalElement,
  present,
  show,
} from '@ibiz/stencil-util';
import anime from 'animejs';

/**
 * 抽屉容器
 *
 * @author chitanda
 * @date 2021-05-31 18:05:41
 * @export
 * @class IBzDrawer
 * @implements {ComponentInterface}
 * @implements {ModalElement}
 */
@Component({
  tag: 'ibz-drawer',
  styleUrl: 'ibz-drawer.scss',
})
export class IBzDrawer implements ComponentInterface, ModalElement {
  @Element()
  el: HTMLIbzDrawerElement;
  ref: HTMLDivElement;

  /**
   * 是否只展示一次，在点击 x 时直接销毁
   *
   * @author chitanda
   * @date 2021-06-02 15:06:11
   * @type {boolean}
   */
  @Prop()
  once: boolean = false;

  @Prop()
  keyboardClose: boolean;

  @Prop()
  overlayIndex: number = 500;

  presented = false;

  @Prop()
  hidden = true;
  @Watch('hidden')
  watchHidden(): void {
    this.updateExp();
    if (this._exp) {
      this._exp.style.visibility = 'visible';
    }
  }

  @Event({ eventName: 'osModalDidDismiss' })
  didDismiss: EventEmitter<any>;

  /**
   * 渲染组件DOM实例
   *
   * @author chitanda
   * @date 2021-04-05 09:04:50
   * @type {HTMLElement}
   */
  usersElement: HTMLElement;

  /**
   * 渲染代理
   *
   * @author chitanda
   * @date 2021-04-05 09:04:57
   * @type {FrameworkDelegate}
   */
  @Prop()
  delegate?: FrameworkDelegate;

  /**
   * 关闭前钩子函数,返回值为是否允许关闭
   *
   * @author zhanghengfeng
   * @date 2023-07-25 11:07:55
   */
  @Prop()
  beforeDismiss?: () => Promise<boolean>;

  /**
   * 需要渲染的组件
   *
   * @author chitanda
   * @date 2021-04-05 09:04:07
   * @type {ComponentRef}
   */
  @Prop()
  component: ComponentRef;

  /**
   * 输入参数
   *
   * @author chitanda
   * @date 2021-04-05 09:04:21
   * @type {*}
   */
  @Prop()
  componentProps: any = {};

  /**
   * 窗口标题
   *
   * @author chitanda
   * @date 2021-06-06 12:06:40
   * @type {string}
   */
  @Prop()
  caption: string;
  @Watch('caption')
  watchCaption(): void {
    forceUpdate(this);
    this.updateExp();
  }

  /**
   * 显示动画起始x轴
   *
   * @author chitanda
   * @date 2021-06-02 15:06:35
   * @type {number}
   */
  @Prop()
  x: number = -1;

  /**
   * 显示动画起始y轴
   *
   * @author chitanda
   * @date 2021-06-02 15:06:45
   * @type {number}
   */
  @Prop()
  y: number = -1;

  /**
   * 扩展样式
   *
   * @type {string}
   * @memberof IBzDrawer
   */
  @Prop()
  exdClass: string = '';

  /**
   * 是否显示头部
   *
   * @type {boolean}
   * @memberof IBzDrawer
   */
  @Prop()
  showHeader: boolean = true;

  /**
   * 是否隐藏导航区
   *
   * @type {boolean}
   * @memberof IBzDrawer
   */
  @Prop()
  showExp: boolean = true;
  
  /**
   * 是否第一次打开
   *
   * @type {boolean}
   * @memberof IBzDrawer
   */
  @Prop()
  first:boolean = true;
  
  _exp: HTMLIbzDrawerExpElement;
  /**
   * 强制更新导航区
   *
   * @author chitanda
   * @date 2021-06-06 12:06:09
   */
  updateExp(): void {
    if (!this._exp) {
      this._exp = document.getElementById('ibz-drawer-exp') as HTMLIbzDrawerExpElement;
    }
    if (this._exp) {
      if (!this.showExp) {
        this._exp.style.visibility = 'hidden';
      } else {
        this._exp.style.visibility = 'visible';
      }
      this._exp.forceUpdate();
    }
  }

  connectedCallback(): void {
    window.addEventListener('keydown', this.onKeydown);
  }

  disconnectedCallback(): void {
    window.removeEventListener('keydown', this.onKeydown);
  }

  onKeydown = (e: KeyboardEvent): void => {
    if (e && e.key === 'Escape' && !this.hidden) {
      if (this.showExp) {
        this.close();
      } else {
        this.hide();
      }
    }
  };

  @Method()
  async present(): Promise<void> {
    if (this.presented) {
      return;
    }
    if (this.component) {
      const componentProps = {
        ...this.componentProps,
        modal: this.el,
      };
      this.usersElement = await attachComponent(
        this.delegate,
        this.ref,
        this.component,
        ['ibz-drawer-content'],
        componentProps,
      );
      await deepReady(this.usersElement);
      writeTask(() => {
        show(this.el);
        this.showAnime();
      });
    } else {
      show(this.el);
      this.showAnime();
    }
    this.el.hidden = false;
    present(this);
  }

  @Method()
  async dismiss(data?: any): Promise<boolean> {
    if (this.beforeDismiss) {
      const result = await this.beforeDismiss();
      if (!result) {
        return;
      }
    }
    if (this.hidden === false) {
      await this.hiddenAnime();
    }
    if (this.component) {
      await dismiss(this, data);
      await detachComponent(this.delegate, this.usersElement);
      // 初始化
      this.el.component = undefined;
      this.componentProps = {};
      writeTask(() => {
        hidden(this.el);
      });
    } else {
      hidden(this.el);
    }
    this.el.hidden = true;
    return true;
  }

  /**
   * 窗口关闭回调[用在已实例化后]
   *
   * @author chitanda
   * @date 2021-04-05 18:04:20
   * @return {*}  {Promise<any>}
   */
  @Method()
  async onDidDismiss(): Promise<any> {
    return eventMethod(this.el, 'osModalDidDismiss');
  }

  /**
   * 显示动画
   *
   * @author chitanda
   * @date 2021-06-02 14:06:21
   */
  showAnime(): Promise<void> {
    return new Promise(resolve => {
      if (this.x >= 0 && this.y >= 0) {
        this.el.style.marginTop = '';
        anime({
          targets: this.el,
          width: '100vw',
          height: '100vh',
          top: [this.y + 'px', '0px'],
          right: [window.innerWidth - this.x + 'px', '0px'],
          opacity: 1,
          easing: 'easeInOutCubic',
          duration: 600,
          complete: () => {
            this.updateExp();
            resolve();
          },
        });
      } else {
        anime({
          targets: this.el,
          'margin-top': ['-100vh', '0vh'],
          easing: 'easeInOutCubic',
          duration: 600,
          complete: () => {
            this.updateExp();
            resolve();
          },
        });
      }
    });
  }
 
  /**
   * 隐藏动画
   *
   * @author chitanda
   * @date 2021-06-02 14:06:26
   * @return {*}  {Promise<void>}
   */
  hiddenAnime(): Promise<void> {
    return new Promise(resolve => {
      if (this.x >= 0 && this.y >= 0) {
        anime({
          targets: this.el,
          width: '0vw',
          height: '0vh',
          top: this.y + 'px',
          right: window.innerWidth - this.x + 'px',
          opacity: 0,
          easing: 'easeInOutCubic',
          duration: 600,
          complete: () => {
            resolve();
          },
        });
      } else {
        anime({
          targets: this.el,
          'margin-top': ['0vh', '-100vh'],
          easing: 'easeInOutCubic',
          duration: 600,
          complete: () => {
            resolve();
          },
        });
      }
    });
  }

  /**
   * 隐藏窗口 「可指定隐藏至的位置」
   *
   * @author chitanda
   * @date 2021-06-02 15:06:23
   * @param {number} [x=-1]
   * @param {number} [y=-1]
   * @return {*}  {Promise<any>}
   */
  @Method()
  async hide(x: number = -1, y: number = -1): Promise<any> {
    if (this.hidden) {
      return;
    }
    this.el.hidden = true;
    if (x >= 0 && y >= 0) {
      this.el.x = x;
      this.el.y = y;
    }
    await this.hiddenAnime();
    hidden(this.el);
  }

  /**
   * 显示窗口「可指定从哪个位置显示」
   *
   * @author chitanda
   * @date 2021-06-02 15:06:20
   * @param {number} [x=-1]
   * @param {number} [y=-1]
   * @return {*}  {Promise<any>}
   */
  @Method()
  async show(x: number = -1, y: number = -1): Promise<any> {
    if (!this.hidden) {
      return;
    }
    this.el.hidden = false;
    if (x >= 0 && y >= 0) {
      this.el.x = x;
      this.el.y = y;
    }
    show(this.el);
    this.showAnime();
  }

  close = (): void => {
    this.dismiss();
  };

  minimize = (): void => {
    this.hide();
  };

  render() {
    return (
      <Host class={`ibz-drawer ${this.exdClass}`} style={{ 'z-index': this.overlayIndex.toString() }}>
        <div class={`ibz-drawer-header ${this.showHeader ? 'show-header' : ''}`}>
          <div class='ibz-drawer-header-caption'>{this.caption}</div>
          {this.once ? null : (
            <div class='ibz-drawer-header-minimize' title='隐藏窗口' onClick={this.minimize}>
              <svg
                class='icon'
                viewBox='0 0 1024 1024'
                version='1.1'
                xmlns='http://www.w3.org/2000/svg'
                width='16'
                height='16'
              >
                <path d='M192.128 448.00000005l639.68 0C867.264 448.00000005 896 476.41600005 896 512.00000005c0 35.392-29.184 64-64.192 64L192.128 576.00000005C156.736 576.00000005 128 547.58400005 128 512.00000005 128 476.60800005 157.184 448.00000005 192.128 448.00000005z'></path>
              </svg>
            </div>
          )}
          <div class='ibz-drawer-header-close' title='关闭窗口' onClick={this.close}>
            <svg
              class='icon'
              viewBox='0 0 1024 1024'
              version='1.1'
              xmlns='http://www.w3.org/2000/svg'
              width='16'
              height='16'
            >
              <path d='M810.666667 273.493333L750.506667 213.333333 512 451.84 273.493333 213.333333 213.333333 273.493333 451.84 512 213.333333 750.506667 273.493333 810.666667 512 572.16 750.506667 810.666667 810.666667 750.506667 572.16 512z'></path>
            </svg>
          </div>
        </div>
        <div
          class={`ibz-drawer-content-wrapper ${!this.showHeader ? 'full-screen' : ''}`}
          ref={ref => (this.ref = ref)}
        ></div>
      </Host>
    );
  }
}
